#ifndef _Hash_H_
#define _Hash_H_

#include "url.hpp"
#include "Log.hpp"
//哈希
class Hash {
public:
	/// @brief 构造器
	Hash ()
	{
		// 初始化CRC表
		for (unsigned int i = 0; i < sizeof(_crcTable) / sizeof(_crcTable[0]); ++i)
		{
			unsigned int crc = i;
			for (unsigned j = 0; j < 8; ++j)
			{		
				if (crc & 1) crc = crc >> 1 ^ 0xEDB88320;
				else crc = crc >> 1;
			}
			_crcTable[i] = crc;
		}
	}

	//Times33哈希算法
	//参数字符串的32位哈希值
	//hash(i) = hash(i-1)×33+str[i] (hash(-1) = 0)
	 ///< [in] 被哈希字符串
	unsigned int times33 (const std::string& str) const
	{
		unsigned int val = 0;
		size_t len = str.size();
		for (size_t i = 0; i < len; ++i)
			val = (val << 5) + val + (unsigned char)str[i];
		return val;
	}

	/// @brief TimesN哈希算法
	/// @return 参数字符串的32位哈希值
	/// @remark  hash(i) = hash(i-1)×N+str[i] (hash(-1) = 0)
	unsigned int timesnum (const std::string& str,int num) const
	{
		unsigned int val = 0;
		size_t len = str.size ();
		for (size_t i = 0; i < len; ++i)
			val = val * num + (unsigned char)str[i];
		return val;
	}

	/// @brief AP哈希算法
	/// @return 参数字符串的32位哈希值
	///< [in] 被哈希字符串
	unsigned int aphash (std::string const& str) const
	{
		unsigned int val = 0;
		size_t len = str.size();
		for (size_t i = 0; i < len; ++i)
		{	
			if (i & 1) val ^= ~(val << 11 ^ (unsigned char)str[i] ^ val >> 5);
			else val ^= val << 7 ^ (unsigned char)str[i] ^ val >> 3;
		}
		return val & 0x7FFFFFFF;
	}

	// FNV哈希算法
// 返回参数字符串的32位哈希值
	unsigned int hash16777619 (std::string const& str) const 
	{
		unsigned int val = 0;
		size_t len = str.size ();
		for (size_t i = 0; i < len; ++i) 
		{
			val *= 16777619;
			val ^= (unsigned char)str[i];
		}
		return val;
	}

// MySQL哈希算法
// 返回参数字符串的32位哈希值
// [输入] 被哈希字符串
	unsigned int mysqlhash(std::string const &str) const
	{
		unsigned int nr1 = 1, nr2 = 4;

		size_t len = str.size();
		for (size_t i = 0; i < len; ++i)
		{
			nr1 ^= ((nr1 & 63) + nr2) * (unsigned char)str[i] + (nr1 << 8);
			nr2 += 3;
		}
		return nr1;
	}
// 循环冗余校验算法
// 返回参数字符串的循环冗余校验码
unsigned int crc32 (std::string const& str) const 
{
	unsigned int val = 0xFFFFFFFF;
	size_t len = str.size ();
	for (size_t i = 0; i < len; ++i)
		val = _crcTable[(val & 0xFF) ^ (unsigned char)str[i]] ^ val >> 8;
	return ~val;
}

private:
	//CRC表
	unsigned int _crcTable[256];
};




/// @brief 布隆过滤器
class UrlFilter {
public:
	/// @brief 析构器
	virtual ~UrlFilter () {}
	//判断某个统一资源定位符是否已经存在
	//存在
	//不存在
	//纯虚函数，子类根据不同过滤器的具体策略给出具体实现
    //统一资源定位符
	virtual bool exist (std::string const& strUrl)	= 0;
};



class BloomFilter : public UrlFilter {
public:
	//构造
	BloomFilter(void){ bzero(m_bloomTable, sizeof(m_bloomTable)); }

	/// @brief 判断某个统一资源定位符是否已经存在
	/// @retval true  存在
	/// @retval false 不存在，同时将其加入布隆表
	/// @note 根据布隆过滤器的策略实现基类中的纯虚函数
	bool exist( std::string const &strUrl)
	{
		// 初始化1位计数器
		int one = 0;

		// 逐个计算哈希值
		for (int i = 0; i < HASH_FUNCS; ++i)
		{
			// 计算哈希值对应的布隆表位数
			unsigned int bit = hash(i, strUrl) % (sizeof(m_bloomTable) * 8);
			// 计算哈希值对应的布隆表元素下标
			unsigned int idx = bit / (sizeof(m_bloomTable[0]) * 8);
			// 计算哈希值对应的布隆表元素中的位数
			bit %= sizeof(m_bloomTable[0]) * 8;

			// 若此位已为1
			if (m_bloomTable[idx] & 0x80000000 >> bit)
				// 1位计数器加1
				++one;
			// 否则
			else
				// 此位置1
				m_bloomTable[idx] |= 0x80000000 >> bit;
		}

		// 若全部哈希值对应的布隆表位都为1，
		// 则返回true，否则返回false
		return one == HASH_FUNCS;
	}

private:
	// 哈希值数
	static int const HASH_FUNCS = 8;
	//布隆表元素数
	static size_t const BLOOMTABLE_SIZE = 1000000;

	/// @brief 用特定的哈希算法计算某个统一资源定位符的哈希值
	/// @return 32位哈希值
	///< [in] 哈希算法标识号
	unsigned int hash(int id,std::string const& strUrl) const
	{
		// 32位哈希值
		unsigned int val = 0;
		// 若哈希算法标识号...
		switch (id)
		{
		// 为0
		case 0:
			// 用Times33算法计算参数统一资源
			// 定位符字符串的32位哈希值
			val = _hash.times33(strUrl);
			break;

		// 为1
		case 1:
			// 用Times31算法计算参数统一资源
			// 定位符字符串的32位哈希值
			val = _hash.timesnum(strUrl, 31);
			break;

		// 为2
		case 2:
			// 用AP算法计算参数统一资源
			// 定位符字符串的32位哈希值
			val = _hash.aphash(strUrl);
			break;

		// 为3
		case 3:
			// 用FNV算法计算参数统一资源
			// 定位符字符串的32位哈希值
			val = _hash.hash16777619(strUrl);
			break;

		// 为4
		case 4:
			// 用MySQL算法计算参数统一资源
			// 定位符字符串的32位哈希值
			val = _hash.mysqlhash(strUrl);
			break;

		// 为5
		case 5:
			// 用循环冗余校验算法计算参数统一资源
			// 定位符字符串的32位哈希值
			val = _hash.crc32(strUrl);
			break;

		// 为6
		case 6:
			// 用Times131算法计算参数统一资源
			// 定位符字符串的32位哈希值
			val = _hash.timesnum(strUrl, 131);
			break;

		// 为7
		case 7:
			// 用Times1313算法计算参数统一资源
			// 定位符字符串的32位哈希值
			val = _hash.timesnum(strUrl, 1313);
			break;

		// 为其它
		default:
			lg(Error, "socker error, %s: %d", strerror(errno), errno);
			// 记录一般错误日志
			// g_app->m_log.printf(Log::LEVEL_ERR, __FILE__, __LINE__,
			// 					"无效哈希算法标识: %d", id);
		}

		// 返回32位哈希值
		return val;
	}

	/// @brief 哈希器
	Hash _hash;
	/// @brief 布隆表
	unsigned int m_bloomTable[BLOOMTABLE_SIZE];
};

class HttpHeader {
public:
	int _statusCode;//状态码
	std::string _contentType;//内容类型
};

//超文本传输协议响应
class HttpResponse 
{
public:
	//构造器
	///dnsurl服务器统一资源定位符
	HttpResponse (const DnsUrl& dnsUrl) 
	: _dnsUrl (dnsUrl), _body (NULL), _len (0) {}

	/// @brief 析构器
	~HttpResponse (void) {
		if (_body) {
			free (_body);
			_body = NULL;
		}
		_len = 0;
	}
	//服务器统一资源定位符
	DnsUrl _dnsUrl;
	//超文本传输协议响应包头
	HttpHeader _header;
	//超文本传输协议响应包体指针
	char* _body;
	//超文本传输协议响应包体长度
	size_t _len;
};

#endif  //_Hash_H_